﻿using Blm.Utils.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using VisionCloud.Domain.DtoModel.MiniApp;
using VisionCloud.Domain.Options;
using VisionSurface.Service.Ms;

namespace VisionSurface.Service.Wx
{
    /// <summary>
    /// 微信API服务
    /// </summary>
    /// <remarks>
    /// 由于此服务已经在Startup使用AddHttpClient<WxApiService>()注入，
    /// 所以在使用Autofac批量注入VisionSurface.Service层服务时，必须排除WxApiService，否则会引起冲突导致报错
    /// </remarks>
    public class WxApiService
    {
        private readonly HttpClient _httpClient;
        private readonly ILogger<WxApiService> logger;
        private readonly WxMessagePushOption wxMessagePushOption;

        /// <summary>
        /// 发送订阅消息的API
        /// </summary>
        const string subscribeSendApi = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={0}";

        /// <summary>
        /// 获取小程序的发送订阅消息的Url
        /// </summary>
        /// <param name="accessToken"></param>
        /// <returns></returns>
        public string GetSubscribeSendApiUrl(string accessToken) => string.Format(subscribeSendApi, accessToken);

        public WxApiService(HttpClient httpClient, ILogger<WxApiService> logger, IOptionsMonitor<WxMessagePushOption> options)
        {
            _httpClient = httpClient;
            this.logger = logger;
            wxMessagePushOption = options.CurrentValue;
        }

        /// <summary>
        /// 加密/校验
        /// </summary>
        /// <param name="signature"></param>
        /// <param name="timestamp"></param>
        /// <param name="nonce"></param>
        /// <returns></returns>
        public bool CheckSignature(string signature, string timestamp, string nonce)
        {
            var stringArray = new[] { wxMessagePushOption.Token, timestamp, nonce };
            Array.Sort(stringArray);
            var combinedString = string.Join("", stringArray);

            using var sha1 = SHA1.Create();
            var hashBytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(combinedString));

            var calculatedSignature = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
            return signature == calculatedSignature;
        }

        /// <summary>
        /// 模板内容
        /// </summary>
        /// <param name="taskInfo"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        public object GetTemplateData(TaskInfoBaseDto taskInfo, string status)
        {
            var length = Math.Min(20, taskInfo.TaskName.Length);
            var projectStage = TaskManageService.ProjectStandardMaps.FirstOrDefault(p => p.ProjectStandardId == taskInfo.ProjectStandardId)?.ProjectStage;
            var stage = projectStage?.ToString() ?? string.Empty;

            /* 注意事项
            character_string：32位以内数字、字母或符号
            thing：20个以内字符
            short_thing：5个以内字符
            */
            return new
            {
                character_string1 = new { value = taskInfo.ProjectNo },
                thing2 = new { value = $"{taskInfo.TaskName.Substring(0, length)}" },
                short_thing6 = new { value = taskInfo.TaskType.ToString() },
                short_thing4 = new { value = stage },
                thing5 = new { value = status },
            };
        }

        /// <summary>
        /// 发送小程序订阅消息
        /// </summary>
        /// <param name="accessToken">接口调用凭证</param>
        /// <param name="openId">接收者（用户）的 openid</param>
        /// <param name="templateId">所需下发的订阅模板id</param>
        /// <param name="data">模板内容，格式形如 { "key1": { "value": any }, "key2": { "value": any } }的object</param>
        /// <param name="page">点击模板卡片后的跳转小程序的页面（目前默认首页）</param>
        /// <returns></returns>
        public async Task SendSubscribeMessageAsync(string accessToken, string openId, string templateId, object data, string page = "pages/index/index")
        {
            HttpResponseMessage response = null;
            try
            {
                var requestContent = new
                {
                    touser = openId,
                    template_id = templateId,
                    page,
                    data,
                    miniprogram_state = "formal",
                    lang = "zh_CN"
                };

                var url = GetSubscribeSendApiUrl(accessToken);
                var httpContent = new StringContent(JsonSerializer.Serialize(requestContent), Encoding.UTF8);
                response = await _httpClient.PostAsync(url, httpContent);
                response.EnsureSuccessStatusCode();

                using var responseContent = await response.Content.ReadAsStreamAsync();
                using var jsonDocument = await JsonDocument.ParseAsync(responseContent);
                var errCode = jsonDocument.RootElement.GetProperty("errcode").GetInt32();
                var errMsg = jsonDocument.RootElement.GetProperty("errmsg").GetString();
                if (errCode != 0)
                {
                    logger.LogError($"发送微信小程序订阅消息失败：errcode = {errCode}，errmsg = {errMsg}");
                }
            }
            catch (Exception ex)
            {
                logger.LogError($"发送微信小程序订阅消息出错：errMessage = {ex.Message + ex.StackTrace}，templateId = {templateId}，data = {data.ToJsonStr()}，StatusCode = {response?.StatusCode}");
            }
        }
    }
}
